{*******************************************************************************
* The contents of this file are used with permission, subject to the Mozilla   *
* Public License Version 1.1 (the "License"); you may not use this file except *
* in compliance with the License. You may obtain a copy of the License at      *
* http://www.mozilla.org/MPL/                                                  *
*                                                                              *
* Software distributed under the License is distributed on an "AS IS" basis,   *
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for *
* the specific language governing rights and limitations under the License.    *
*                                                                              *
* The Original Code is distributed as part of the "mediate" product and is     *
* Copyright (C) @home media limited. All Rights Reserved.                      *
*                                                                              *
* Email: support@athomemedia.co.uk                                             *
* Web:   http://www.athomemedia.co.uk                                          *
*******************************************************************************}

unit ScreenForm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, AppEvnts, ImgList, Menus;

type
  TAHMScreenForm = class(TForm)
    PopupMenu: TPopupMenu;
    miSettings: TMenuItem;
    N2: TMenuItem;
    miAbout: TMenuItem;
    miSupport: TMenuItem;
    N1: TMenuItem;
    miExit: TMenuItem;
    ImageList: TImageList;
    ApplicationEvents: TApplicationEvents;
    TrayIcon1: TTrayIcon;
    N3: TMenuItem;
    miRestart: TMenuItem;
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormDblClick(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
      WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
    procedure ApplicationEventsActivate(Sender: TObject);
    procedure ApplicationEventsDeactivate(Sender: TObject);
    procedure ApplicationEventsIdle(Sender: TObject; var Done: Boolean);
    procedure ApplicationEventsException(Sender: TObject; E: Exception);
    procedure ApplicationEventsMinimize(Sender: TObject);
    procedure ApplicationEventsRestore(Sender: TObject);
    procedure miSettingsClick(Sender: TObject);
    procedure miAboutClick(Sender: TObject);
    procedure miSupportClick(Sender: TObject);
    procedure miExitClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure ApplicationEventsMessage(var Msg: tagMSG; var Handled: Boolean);
    procedure FormShow(Sender: TObject);
    procedure miRestartClick(Sender: TObject);
  private
    { Private declarations }
    FMouseStartX: Integer;
    FMouseStartY: Integer;
    FFullscreen: Boolean;
//    FOldX, FOldY, FOldW, FOldH: Integer;
    FBombing: Boolean;
    procedure ApplicationHibernate;
    procedure ApplicationResume;
  protected
    { Protected declarations }
    procedure CMDialogKey(var Msg: TWMKey); message CM_DIALOGKEY;
    procedure WMSysCommand(var Msg: TWmSysCommand); message WM_SYSCOMMAND;
    procedure PowerMessage(var Msg: TWMPower); message WM_POWERBROADCAST;
    procedure CreateParams(var Params: TCreateParams); override;
  public
    { Public declarations }
    procedure SetSize(Width, Height: Integer);
    procedure ConfigureForm(Fullscreen: Boolean);
  end;

var
  AHMScreenForm: TAHMScreenForm;

implementation

{$R *.dfm}

uses ApplicationManager, Messaging, Screen, Logging, Utilities, ErrorForm,
     SingleInstance, AHMConsts, AHMTypes;

//-----------------------------------------------------------------------------
//----------------------------- Form Events -----------------------------------
//-----------------------------------------------------------------------------

procedure TAHMScreenForm.CreateParams(var Params: TCreateParams);
begin
  // Tweak window flags to make this appear as an app window on taskbar
  inherited CreateParams(Params);

  if not (Assigned(ApplicationManagerInstance) and ApplicationManagerInstance.DesignerMode) then
    Params.ExStyle := Params.ExStyle and not WS_EX_TOOLWINDOW or WS_EX_APPWINDOW;
end;

procedure TAHMScreenForm.FormCreate(Sender: TObject);
begin
  // Create global application manager instance
  TAHMApplicationManager.CreateInstance;

  // Fix extra taskbar window under Vista
  if not ApplicationManagerInstance.DesignerMode then
    RemoveApplicationWindowFromTaskBar;

  // Hookup screen rendering to this form
  ScreenInstance.ScreenForm := Self;
end;

procedure TAHMScreenForm.FormDestroy(Sender: TObject);
begin
  // Free our application manager instance
  TAHMApplicationManager.DestroyInstance;
end;

procedure TAHMScreenForm.FormShow(Sender: TObject);
begin
  // Check for configuration or shutdown switches on command line
  if FindCmdLineSwitch(SWITCH_CONFIGURE, True) then
  begin
    // Configure other instance if found, otherwise configure this instance
    if PreviousApplicationInstance and (PreviousInstanceHandle <> 0) then
      MessengerInstance.RequestMediateConfigure(PreviousInstanceHandle)
    else
      ApplicationManagerInstance.ConfigureSettings;
    Halt;
  end
  else if FindCmdLineSwitch(SWITCH_SHUTDOWN, True) then
  begin
    // Shutdown this and any other running instances
    MessengerInstance.RequestMediateShutdown;
    Halt;
  end
  else if FindCmdLineSwitch(SWITCH_REGISTER, True) then
  begin
    // Register mediate filetypes then quit
    SetAssociatedApp(Application.ExeName, EXT_THEMEARC, 'mediate Theme Archive');
    Halt;
  end
  else if PreviousApplicationInstance then
  begin
    // Another instance of mediate is running, so try to bring that to front
    if PreviousInstanceHandle = 0 then
    begin
      // Couldn't find other instance for some reason, so show message
      MessageDlg('mediate appears to be already running. Only one instance of ' +
                 'mediate is allowed to run at a time.', mtWarning, [mbAbort], 0);
    end
    else
      MessengerInstance.RequestMediateLaunch;
    Halt;
  end
  else if Pos(EXT_THEMEARC, ParamStr(1)) > 0 then
  begin
    // Theme archive file passed on command line, so import it
    ApplicationManagerInstance.ImportTheme(ParamStr(1));
    Halt;
  end;

  // If not halted by this point then launch main app
  ApplicationManagerInstance.Launch;
end;

procedure TAHMScreenForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  // Ask the application manager to shutdown the application gracefully
  ApplicationManagerInstance.ShutDown;
end;

procedure TAHMScreenForm.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  // If Application manager handles the keypress then inhibit form handling
  if ApplicationManagerInstance.ProcessKeyPress(Key, Shift) then
    Key := 0;
end;

procedure TAHMScreenForm.FormMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  // Record mouse start coordinate for dragging
  FMouseStartX := X;
  FMouseStartY := Y;

  // Pass left mouse events to application manager to handle
  if ssLeft in Shift then
    ApplicationManagerInstance.ProcessMouseDown(X, Y)
  else if ssRight in Shift then
    if ApplicationManagerInstance.PreferencesManager.MouseRightAction = mrMenu then
      ApplicationManagerInstance.ProcessMouseMenu;
end;

procedure TAHMScreenForm.FormMouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
var
  LeftButtonDown: Boolean;
begin
  // If right mouse button held drag form, otherwise pass to application manager
  if ssRight in Shift then
  begin
    // Drag form position when running in windowed mode only
    if (not FFullScreen) and (WindowState <> wsMaximized) then
      if ApplicationManagerInstance.PreferencesManager.MouseRightAction = mrDrag then
      begin
        Left := Left + X - FMouseStartX;
        Top := Top + Y - FMouseStartY;
      end;
  end
  else
  begin
    LeftButtonDown := ssLeft in Shift;
    ApplicationManagerInstance.ProcessMouseMove(X, Y, LeftButtonDown);
  end;
end;

procedure TAHMScreenForm.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  // Check that left mouse button was released then pass to application manager
  if Button = mbLeft then
    ApplicationManagerInstance.ProcessMouseUp(X, Y);
end;

procedure TAHMScreenForm.FormMouseWheel(Sender: TObject; Shift: TShiftState;
  WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
begin
  // Pass mouse wheel events to application manager to handle
  ApplicationManagerInstance.ProcessMouseWheel(WheelDelta);
end;

procedure TAHMScreenForm.FormDblClick(Sender: TObject);
begin
(* FIXME - either implement or remove code
  if not FFullScreen then
    if WindowState = wsMaximized then WindowState := wsNormal
    else WindowState := wsMaximized;
*)

(* disabled for now - we need to stop video in order to reset DirectX which
   leads to a confusing user experience. Will revisit this post 1.4.0 release

  // Toggle between normal window and maximised states unless fullscreen
  if not FFullScreen then
  begin
    if WindowState = wsMaximized then WindowState := wsNormal
    else if WindowState = wsNormal then
    begin
      // Preserve window position/dimensions
      FOldX := Left; FOldY := Top; FOldW := Width; FOldH := Height;
      WindowState := wsMaximized;
    end;

    // Reconfigure form border
    ConfigureForm(FFullscreen);
    ScreenInstance.ResetDisplay;

    // Restore window position/dimensions if returning from 'fullscreen'
    if WindowState = wsNormal then
    begin
      Left := FOldX; Top := FOldY; Width := FOldW; Height := FOldH;
    end;
  end;
//*)
end;

//-----------------------------------------------------------------------------
//----------------------------- Menu Events -----------------------------------
//-----------------------------------------------------------------------------

procedure TAHMScreenForm.miAboutClick(Sender: TObject);
begin
  // Display mediate about dialog
  ApplicationManagerInstance.DisplayAbout;
end;

procedure TAHMScreenForm.miExitClick(Sender: TObject);
begin
  // Quit mediate - save state first
  ApplicationManagerInstance.Terminate;
end;

procedure TAHMScreenForm.miRestartClick(Sender: TObject);
begin
  // Restart mediate
  ApplicationManagerInstance.Restart;
end;

procedure TAHMScreenForm.miSettingsClick(Sender: TObject);
begin
  // Display mediate advanced settings dialog
  ApplicationManagerInstance.ConfigureSettings;
end;

procedure TAHMScreenForm.miSupportClick(Sender: TObject);
begin
  // Launch mediate support in browser
  DisplayBrowserSupport;
end;

//-----------------------------------------------------------------------------
//-------------------------- Application Events -------------------------------
//-----------------------------------------------------------------------------

procedure TAHMScreenForm.ApplicationEventsActivate(Sender: TObject);
begin
//TODO fix this
  // Inform application manager we regained focus
//  if not Application.Terminated then ApplicationManagerInstance.AppActivated;
end;

procedure TAHMScreenForm.ApplicationEventsDeactivate(Sender: TObject);
begin
//TODO fix this
  // Inform application manager we lost focus
//  if not Application.Terminated then ApplicationManagerInstance.AppDeactivated;
end;

procedure TAHMScreenForm.ApplicationEventsException(Sender: TObject;
  E: Exception);
begin
  // Ignore any secondary error messages
  if FBombing then Exit else FBombing := True;

  // Write exception details to our log
  LogError('Unhandled exception: ' + E.Message);

  // Ask application manager to halt & quit rendering
  ApplicationManagerInstance.Halt;

  // Provide visual notification of error message - allow option to close app.
  TfrmError.ShowError(E.Message);

  // Uncontrolled exit...
  Halt;
end;

procedure TAHMScreenForm.ApplicationEventsIdle(Sender: TObject;
  var Done: Boolean);
begin
  // Render mediate user interface if required
  if Assigned(ApplicationManagerInstance) then
    if ApplicationManagerInstance.RenderFrame then
      Done := False; // Keep looping
end;

procedure TAHMScreenForm.ApplicationEventsMessage(var Msg: tagMSG;
  var Handled: Boolean);
begin
  // Ask our message handler to check the message received
  case MessengerInstance.HandleMessage(Msg, Handled) of
    mtMediateShutdown: Application.Terminate;
    mtMediateLaunch: ApplicationManagerInstance.Launch;
    mtMediateConfigure: ApplicationManagerInstance.ConfigureSettings;
    mtMediateRemote: ApplicationManagerInstance.ProcessRemoteCommand(Msg.wParam);
  end;
end;

procedure TAHMScreenForm.ApplicationEventsMinimize(Sender: TObject);
begin
  // Inform application manager instance we were minimized
  ApplicationManagerInstance.SuspendRendering;
end;

procedure TAHMScreenForm.ApplicationEventsRestore(Sender: TObject);
begin
  // Inform application manager instance we were restored
  ApplicationManagerInstance.ResumeRendering;
end;

procedure TAHMScreenForm.ApplicationHibernate;
begin
  if Assigned(ApplicationManagerInstance) then
    ApplicationManagerInstance.AppHibernating;
end;

procedure TAHMScreenForm.ApplicationResume;
begin
  if Assigned(ApplicationManagerInstance) then
    ApplicationManagerInstance.AppResumed;
end;

//-----------------------------------------------------------------------------
//------------------------- Miscellaneous Events ------------------------------
//-----------------------------------------------------------------------------

procedure TAHMScreenForm.CMDialogKey(var Msg: TWMKey);
begin
  // Inhibit standard handling of tab key so it sends a key event instead
  if Msg.CharCode = VK_TAB then
    Msg.CharCode := 0
  else
    inherited;
end;

procedure TAHMScreenForm.WMSysCommand(var Msg: TWmSysCommand);
begin
  // Override standard delphi handling to get proper effects under Vista
  case (Msg.CmdType and $FFF0) of
    SC_MINIMIZE:
    begin
      ShowWindow(Handle, SW_MINIMIZE);
      Msg.Result := 0;
    end;
    SC_RESTORE:
    begin
      ShowWindow(Handle, SW_RESTORE);
      Msg.Result := 0;
    end;
  else
    inherited;
  end;
end;

procedure TAHMScreenForm.PowerMessage(var Msg: TWMPower);
const
  WIN32VERSION_NT = 4;
  PBT_APMSUSPEND = 4;
  PBT_APMRESUMEAUTOMATIC = 18;
begin
  // Check message param for details of power event
  if Win32MajorVersion = WIN32VERSION_NT then
    case Msg.PowerEvt of
      PWR_SUSPENDREQUEST: ApplicationHibernate;
      PWR_CRITICALRESUME, PWR_SUSPENDRESUME: ApplicationResume;
    end
  else
    case Msg.PowerEvt of
      PBT_APMSUSPEND: ApplicationHibernate;
      PBT_APMRESUMEAUTOMATIC: ApplicationResume;
    end;

  // Indicate message handled
  Msg.Result := PWR_OK;
end;

//-----------------------------------------------------------------------------
//--------------------- User Interface Configuration --------------------------
//-----------------------------------------------------------------------------

procedure TAHMScreenForm.SetSize(Width, Height: Integer);
begin
  // Set form size
  Self.ClientWidth := Width;
  Self.ClientHeight := Height;
  Left := 0;
  Top := 0;
end;

procedure TAHMScreenForm.ConfigureForm(Fullscreen: Boolean);
begin
  with ApplicationManagerInstance do
    begin
      // Configure form border style
      if Fullscreen then BorderStyle := bsNone
      else if PreferencesManager.HideWindowBorder then BorderStyle := bsNone
      else BorderStyle := bsSizeable;

      // Should we maximize form?
      if (not Fullscreen) and PreferencesManager.MaximizeWindow then
        WindowState := wsMaximized
      else
        WindowState := wsNormal;

      // Configure form style
      if Fullscreen then FormStyle := fsStayOnTop
      else FormStyle := fsNormal;

      // Store fullscreen property
      FFullscreen := Fullscreen;
    end;
end;


end.
